<?php
/**
 * Created by PhpStorm.
 * User: bzg
 * Date: 2019/11/28
 * Time: 14:47
 */

namespace App\Model;


use App\Common\Exception\ServiceRunTimeException;
use EasySwoole\ORM\AbstractModel;

class BaseModel extends AbstractModel
{
    // 自动时间戳
    protected $autoTimeStamp = true;
    // 时间戳字段
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';

    /**
     * 新增更新一条记录
     * @param array $data 记录数组
     * @param array $check 检查更新条件
     * @param bool $use_set 是否使用修改器
     * @return bool|int
     * @throws \EasySwoole\Mysqli\Exception\Exception
     * @throws \EasySwoole\ORM\Exception\Exception
     * @throws \Throwable
     */
    public function saveRow(array $data,array $check = [], bool $use_set = true)
    {
        // 判断是新增还是更新
        $pk = $this->schemaInfo()->getPkFiledName();
        // 新增操作
        if(empty($data[$pk])) {
            // 返回主键
            return static::create()->data($data, $use_set)->save();
        }
        // 更新操作
        else {
            $model = static::create()->get($data[$pk]);
            if(!$model) {
                throw new ServiceRunTimeException('未查询到该记录');
            }
            $this->check($model,$check);
            unset($data[$pk]);
            // 返回布尔值
            return $model->update($data);
        }
    }

    /**
     * 构造条件
     * @param array $request 请求参数数组
     * @param array $field 条件字段数组
     *  [
     *      [
     *          数据库字段名,
     *          对比条件,
     *          前端传来的键名 | 当对比条件为bt时： [开始键名，结束键名] | 开始键名
     *      ]
     *  ]
     * @param string $as 表别名
     * @return BaseModel
     */
    public function makeWhere(array $request,array $field, string $as = '')
    {
        if(!empty($field) && !empty($request)) {
            foreach ($field as $v) {
                // 兼容【表别名.字段名写法】
                $field_arr = explode('.',$v[0]);
                if(count($field_arr) == 2) {
                    $v[0] = $field_arr[1]; // 字段名
                    $as = $field_arr[0]; // 别名
                }
                // 判断前端给的键名
                $key = empty($v[2]) ? $v[0] : $v[2];
                // 判断条件，如果条件为空，默认为=
                $v[1] = empty($v[1]) ? '=' : $v[1];

                if (!empty($request[$key]) || in_array($v[1],['like','bt'])) {
                    // 将字段名组装为 表明.字段名
                    if ($as) $f = $as . '.' . $v[0];
                    else $f = $v[0];
                    switch ($v[1]) {
                        case 'like': // like字段
                            $key = empty($v[2]) ? 'key' : $v[2];
                            if (!empty($request[$key])) {
                                $this->where($f, '%' . $request[$key] . '%', $v[1]);
                            }
                            break;

                        case 'bt': // 在**之间，默认前端字段为start,end
                            // 给默认值
                            if(empty($v[2])) {
                                $v[2] = ['start','end'];
                            }
                            // 解析规则
                            if(is_array($v[2])) {
                                if(!empty($request[$v[2][0]]) && !empty($request[$v[2][1]])){
                                    $this->where($f, $request[$v[2][0]], '>=');
                                    $this->where($f, $request[$v[2][1]], '<');
                                }
                            }elseif(is_string($v[2])){
                                if(!empty($request[$v[2]])){
                                    $this->where($f, $request[$v[2]], '>=');
                                }
                            }
                            break;

                        default: // in,>,>=,<,<=字段
                            $this->where($f, $request[$key], $v[1]);
                            break;
                    }
                }
            }
        }
        return $this;
    }


    /**
     * 修改状态
     * @param int|string $id 记录ID
     * @param string|array $field 修改的字段 (为字符串则是修改的字段名，默认1和2切换，为数组则指定字段指定值['字段'=>值,])
     * @param array $check 验证条件 ['需验证的字段'=>'值',]
     * @return bool
     * @throws ServiceRunTimeException
     * @throws \EasySwoole\Mysqli\Exception\Exception
     * @throws \EasySwoole\ORM\Exception\Exception
     * @throws \Throwable
     */
    public function saveStatus($id, $field = 'status', array $check = [])
    {
        $model = static::create()->get($id);
        if(!$model) {
            throw new ServiceRunTimeException('未查询到该记录');
        }
        $this->check($model,$check);
        $data = [];
        if(is_array($field)) {
            foreach ($field as $f => $v) {
                $data[$f] = $v;
            }
        }else{
            $data[$field] = $model->$field == 1 ? 2 : 1;
        }
        // 返回布尔值
        return $model->update($data);
    }

    /**
     * 删除记录
     * @param mixed $id 记录ID或者数组
     * @param array $check 校验条件
     * @return int|null
     * @throws ServiceRunTimeException
     * @throws \EasySwoole\Mysqli\Exception\Exception
     * @throws \EasySwoole\ORM\Exception\Exception
     * @throws \Throwable
     */
    public function delete($id ,array $check = [])
    {
        $pk = $this->schemaInfo()->getPkFiledName();
        if(is_array($id)) {
            // 查询出数组中的记录
            $rows = static::create()->where($pk,$id,'in')->all();
            if($rows) {
                foreach ($rows as $row) {
                    $this->check($row, $check);
                }
            }
            return static::create()->destroy($id);
        }else{
            $model = static::create()->get($id);
            $this->check($model,$check);
            return $model->destroy();
        }
    }

    /**
     * 分页
     * @param int $limit 每页记录数
     * @param int $page 当前页
     * @return array
     * @throws \EasySwoole\ORM\Exception\Exception
     * @throws \Throwable
     */
    public function paginate(int $limit,int $page)
    {
        $this->limit($limit * ($page - 1), $limit)->withTotalCount();
        // 列表数据
        $list = $this->all(null, true);
        $result = $this->lastQueryResult();
        // 总条数
        $total = $result->getTotalCount();
        return [
            'total'      => $total, // 总记录数
            'current_page'    => $page, // 当前页码
            'per_page'      => $limit, // 每页记录数
            'last_page' => ceil($total/$limit), // 总页数
            'data'       => $list // 数据
        ];
    }


    /**
     * 检查修改条件
     * @param BaseModel $model 模型
     * @param array $check 检查条件 [字段名 => 值|允许的值的数组]
     * @throws ServiceRunTimeException
     */
    private function check(BaseModel $model, array $check)
    {
        if(!empty($check)) {
            foreach ($check as $k => $v) {
                if(is_array($v)) {
                    $re = in_array($model->$k, $v);
                }else{
                    $re = $model->$k == $v;
                }
                if(!$re) {
                    throw new ServiceRunTimeException('非法的修改');
                }
            }
        }
    }
}